using System;


namespace epicenter2010.Common
{
	/// <summary>
	/// bstack @ 06/06/2010
	/// Based on Meyer's design by contract check based implementation.
	/// Require is for pre-conditions
	/// Invariant is for invariant conditions
	/// Ensure is for post conditions
	/// </summary>
	public static class DBCChecker
	{
		/// <summary>
		/// Generic pre-condition
		/// </summary>
		/// <param name="isConditionSatisfied"></param>
		/// <param name="conditionFailureMessage"></param>
		/// <param name="conditionFailureMessageItems">Items for a format string template where the condition failure message is a template</param> 
		public static void Require(
			bool isConditionSatisfied,
			string conditionFailureMessage,
			params object[] conditionFailureMessageItems)
		{
			if (isConditionSatisfied)
			{
				return;
			}

			conditionFailureMessage = epicenter2010.Common.DBCChecker.BuildMessage(conditionFailureMessage, conditionFailureMessageItems); 
			
			throw new Exception(conditionFailureMessage);
		}


		/// <summary>
		/// Argument is not null pre-condition (This is a very common special case, where we throw a very specific exception)
		/// </summary>
		/// <param name="argumentName"></param>
		/// <param name="argumentValue"></param>
		public static void RequireArgumentNotNull(
			string argumentName,
			object argumentValue)
		{
			if (argumentValue != null)
			{ 
				return; 
			}

			throw new ArgumentNullException(argumentName); 
		}


		/// <summary>
		/// Argument is not an empty string pre-condition (This is a very common special case, where we throw a very specific exception)
		/// </summary>
		/// <param name="argumentName"></param>
		/// <param name="argumentValue"></param>
		public static void RequireArgumentNotEmpty(
			string argumentName,
			string argumentValue)
		{
			if (argumentValue == null)
			{
				throw new ArgumentNullException(argumentName);
			}
			if (argumentValue.Length == 0)
			{
				throw new ArgumentOutOfRangeException(argumentName, "Cannot be empty!");
			}
		}


		/// <summary>
		/// Argument pre-condition (This is a very common special case, where we throw a very specific exception)
		/// </summary>
		/// <param name="argumentName"></param>
		/// <param name="isConditionSatisfied"></param>
		/// <param name="conditionFailureMessage"></param>
		/// <param name="conditionFailureMessageItems">Items for a format string template where the condition failure message is a template</param> 
		public static void RequireArgument(
			string argumentName,
			bool isConditionSatisfied,
			string conditionFailureMessage,
			params object[] conditionFailureMessageItems)
		{
			if (isConditionSatisfied)
			{ 
				return; 
			}

			conditionFailureMessage = epicenter2010.Common.DBCChecker.BuildMessage(conditionFailureMessage, conditionFailureMessageItems); 

			throw new ArgumentException(conditionFailureMessage, argumentName);
		}


		/// <summary>
		/// Invariant
		/// </summary>
		/// <param name="isConditionSatisfied"></param>
		/// <param name="conditionFailureMessage"></param>
		/// <param name="conditionFailureMessageItems">Items for a format string template where the condition failure message is a template</param> 
		public static void Invariant(
			bool isConditionSatisfied,
			string conditionFailureMessage,
			params object[] conditionFailureMessageItems)
		{
			if (isConditionSatisfied)
			{
				return;
			}

			conditionFailureMessage = epicenter2010.Common.DBCChecker.BuildMessage(conditionFailureMessage, conditionFailureMessageItems);

			throw new Exception(conditionFailureMessage);
		}


		/// <summary>
		/// Generic post-condition
		/// </summary>
		/// <param name="isConditionSatisfied"></param>
		/// <param name="conditionFailureMessage"></param>
		/// <param name="conditionFailureMessageItems">Items for a format string template where the condition failure message is a template</param> 
		public static void Ensure(
			bool isConditionSatisfied,
			string conditionFailureMessage,
			params object[] conditionFailureMessageItems)
		{
			if (isConditionSatisfied)
			{
				return;
			}

			conditionFailureMessage = epicenter2010.Common.DBCChecker.BuildMessage(conditionFailureMessage, conditionFailureMessageItems);

			throw new Exception(conditionFailureMessage);
		}


		/// <summary>
		/// Build message, we expect that the compiler will inline this method anyway
		/// </summary>
		/// <param name="conditionFailureMessage"></param>
		/// <param name="conditionFailureMessageItems">Items for a format string template where the condition failure message is a template</param> 
		/// <returns></returns> 
		private static string BuildMessage(
			string conditionFailureMessage,
			params object[] conditionFailureMessageItems)
		{
			if (string.IsNullOrEmpty(conditionFailureMessage))
			{
				return conditionFailureMessage;
			}

			if (conditionFailureMessageItems != null)
			{
				return string.Format(conditionFailureMessage, conditionFailureMessageItems);
			}
			else
			{
				return conditionFailureMessage;
			}
		}
	}
}
